﻿
namespace Patterns4Net.ArchitectureExplorer.ViewModels
{
    using System.ComponentModel.Composition;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Controls;
    using Caliburn.Micro;
    using Patterns4Net.ArchitectureExplorer.Diagram;
    using Patterns4Net.ArchitectureExplorer.Documentation;
    using Patterns4Net.ArchitectureExplorer.ViewModels.Messages;
    using Patterns4Net.ArchitectureExplorer.ViewModels.Services;

    [Export(typeof(PatternDocumentationPanelViewModel))]
    public class PatternDocumentationPanelViewModel : PropertyChangedBase, IHandle<DiagramElementSelectedMessage>
    {
        private readonly IPatternDocProvider patternDocProvider;

        private readonly DocumentationParser docParser;

        private List<PatternDocumentationViewModel> patternsDocumentation;

        private DiagramElement currentElement;

        private PatternDocumentationViewModel selectedPattern;

        [ImportingConstructor]
        public PatternDocumentationPanelViewModel(
            IPatternDocProvider patternDocProvider, 
            DocumentationParser docParser,
            IEventAggregator eventAggregator)
        {
            this.patternDocProvider = patternDocProvider;
            this.docParser = docParser;
            eventAggregator.Subscribe(this);
        }

        public PatternDocumentationViewModel SelectedPattern
        {
            get { return this.selectedPattern; }
            set
            {
                this.selectedPattern = value;
                this.NotifyOfPropertyChange(() => this.SelectedPattern);
            }
        }

        public IEnumerable<PatternDocumentationViewModel> PatternsDocumentation
        {
            get
            {
                if (this.currentElement is TypeInfo == false)
                {
                    return Enumerable.Empty<PatternDocumentationViewModel>();
                }

                if (this.patternsDocumentation == null)
                {
                    this.patternsDocumentation = new List<PatternDocumentationViewModel>();
                    var typeInfo = (TypeInfo)this.currentElement;
                    foreach (var pattern in typeInfo.Patterns)
                    {
                        AddPatternDocumentation(pattern);
                    }

                    var methodPatterns = typeInfo.Methods
                        .SelectMany(m => m.Patterns.Select(p => new { Method = m, Pattern = p }))
                        .GroupBy(p => p.Pattern.GetType());
                    foreach (var methodPattern in methodPatterns)
                    {
                        var doc = AddPatternDocumentation(methodPattern.First().Pattern);
                        doc.Methods = methodPattern.Select(x => x.Method);
                    }
                }

                return this.patternsDocumentation;
            }
        }

        private PatternDocumentationViewModel AddPatternDocumentation(PatternInfo pattern)
        {
            var doc = this.patternDocProvider.GetDocumentation(pattern.Pattern);
            var name = pattern.Pattern.Name;
            TextBlock xamlDoc = null;
            if (doc != null)
            {
                xamlDoc = this.docParser.Transform(doc);
            }

            var result = new PatternDocumentationViewModel(name, xamlDoc);
            this.patternsDocumentation.Add(result);
            return result;
        }

        public void Handle(DiagramElementSelectedMessage message)
        {
            this.currentElement = message.DiagramElement;
            this.patternsDocumentation = null;
            this.SelectedPattern = this.PatternsDocumentation.FirstOrDefault();
            this.NotifyOfPropertyChange(() => this.PatternsDocumentation);
        }
    }
}
